<?php
declare (strict_types = 1);
namespace app\common\controller;
use think\App;
use think\Validate;
use Legolas3703\ThinkValidateExtend\Rules;
use app\common\model\Debug;
use app\common\model\ErrLog;

/**
 * 控制器基础类
 */
class Base
{
	/**
	 * Request实例
	 * @var \think\Request
	 */
	protected $request;


	/**
	 * 应用实例
	 * @var \think\App
	 */
	protected $app;


	/**
	 * 控制器中间件
	 * @var array
	 */
	protected $middleware = [
		// 验证器中间件（需要获取控制器、方法名，必须在路由解析完成后执行。所以只能定义为控制器中间件）
		'app\common\middleware\Check'
	];


	/**
	 * 构造方法
	 * @access public
	 * @param App $app 应用对象
	 */
	public function __construct(App $app)
	{
		$this->app = $app;
		$this->request = $this->app->request;
		// 从Composer扩展加载额外的验证器规则
		new Rules();
		// 加载项目级验证器规则
		$this->loadExtraValidateRules();
	}


	/**
	 * 加载额外的验证器规则（ 仅在当前项目内复用至不同接口，不需要在扩展内实现）
	 */
	private function loadExtraValidateRules()
	{
		// 验证方法列表
		$method_list = [
			'checkRequestTime'
		];

		// 将扩展规则注入验证器
		Validate::maker(
			function($validate) use ($method_list)
			{
				foreach($method_list as $key=>$val)
				{
					$callable = [$this, $val];
					$validate->extend($val, $callable);
				}
			}
		);
	}


	/**
	 * 自定义验证方法：检查请求时间
	 * 以服务器时间为基准，±5分钟
	 */
	public function checkRequestTime($value)
	{
		$server_time = time();
		$time_interval_start = $server_time - 300;
		$time_interval_end = $server_time + 300;
		if( ($value < $time_interval_start) || ($value > $time_interval_end) )
		{
			return false;
		}

		return true;
	}


	/**
	 * 保存日志到数据库
	 * @param Int $level 日志等级 [1-错误 2-调试信息（默认）]
	 * @param Mixed $custom_data 自定义数据
	 * @return Bool
	 */
	static public function saveLog(int $level=2, $custom_data='')
	{
		$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
		$line = $stack[0]['line'];
		$caller = $stack[1]['class'];
		$function = $stack[1]['function'];

		$host = Request()->host();
		$url = Request()->url();

		// 处理自定义数据
		$custom_data = [
			'custom_data' => $custom_data
		];

		// 组装数据
		$timestamp = time();
		$data = [
			'date' => date('Y-m-d H:i:s', $timestamp),
			'ip' => Request()->ip(),
			'url' => "{$host}{$url}",
			'path' => "{$caller}\\{$function}",
			'line' => $line,
			'request_data' => json_encode((array)Request(), JSON_UNESCAPED_UNICODE),
			'get_data' => json_encode(input('get.'), JSON_UNESCAPED_UNICODE),
			'post_data' => json_encode(input('post.'), JSON_UNESCAPED_UNICODE),
			'custom_data' => json_encode($custom_data, JSON_UNESCAPED_UNICODE),
			'create_time' => $timestamp
		];

		// 根据日志等级，选择存储位置
		switch($level)
		{
			case 1:
				$log_table = new ErrLog();
				break;
			case 2:
				$log_table = new Debug();
				break;
		}

		$table_suffix = date('_Y', $timestamp);
		$save_log = $log_table
			->setSuffix($table_suffix)
			->save($data);
		return $save_log ? true : false;
	}


}
